package testes;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import baseClass.*;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
 * 
 * @author Carlos Victor
 *
 */
public class RecomendacoesTest {
	
	Recomendacoes recomendacoes,recomendacoes2;
	
	/**
	 * Cria as recomdancoes.
	 * @throws Exception
	 * 		Caso as opnioes e os estabelecimentos sejam nulos ou vazios.
	 */
	@Before
	public void CriaRecomendacoes() throws Exception{
			recomendacoes = new Recomendacoes("Opinioes-v2.data","Estabelecimentos-v2.data");
	}
		
	/**
	 * Testa os tratamentos de erro no construtor.
	 */
	@Test
	public void testaErroNoConstrutor(){
			try {
				recomendacoes2 = new Recomendacoes("","Estabelecimentos-v2.data");
				Assert.fail("Espera excecao de opinioes vazia.");
			} catch (Exception e) {
				Assert.assertEquals("Erro no Construtor", "arquivo de opnioes nao pode ser nulo ou vazio.",e.getMessage());
			}
			
			try {
				recomendacoes2 = new Recomendacoes(null,"Estabelecimentos-v2.data");
				Assert.fail("Espera excecao de opinioes vazia.");
			} catch (Exception e) {
				Assert.assertEquals("Erro no Construtor", "arquivo de opnioes nao pode ser nulo ou vazio.",e.getMessage());
			}
			try {
				recomendacoes = new Recomendacoes("Opinioes-v2.data","");
			} catch (Exception e) {
				Assert.assertEquals("Erro no Construtor", "arquivo de enderecos nao pode ser nulo ou vazio.",e.getMessage());
			}
			
			try {
				recomendacoes = new Recomendacoes("Opinioes-v2.data",null);
			} catch (Exception e) {
				Assert.assertEquals("Erro no Construtor", "arquivo de enderecos nao pode ser nulo ou vazio.",e.getMessage());
			}
		}
		
	/**
	 * Testa o caminho do arquivo de opinioes.
	 */
	@Test
	public void testGetCaminhoArquivo1(){
		Assert.assertEquals("Erro no caminho de arquivo 1", "Opinioes-v2.data",recomendacoes.getCaminhoArquivo1());
	}
		
	/**
	 * testa caminho do arquivo de estabelecimentos.
	 */
	@Test
	public void testGetCaminhoArquivo2() {
		Assert.assertEquals("Erro no caminho de arquivo 1", "Estabelecimentos-v2.data",recomendacoes.getCaminhoArquivo2());
	}

	/**
	 * testa os usuarios presente no sistema.
	 */
	@Test
	public void testGetUsuarios() {
		
		int indice = 0;
		Arquivo a = new Arquivo();
		try {
			a.lerArquivo("Opinioes-v2.data");
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		List<String> linhas = a.getLinhasDoArquivoLido();
		List<User> usuarios = new ArrayList<User>();
		
		for (int i = 1; i < linhas.size(); i++) {
			String[] infos = linhas.get(i).split(";");
			Map<String,Integer> opnioes = new HashMap<String,Integer>(); 
			String nome = infos[1];
			if (nome.isEmpty()) {
				nome = "Anonimo" + indice;
				indice ++;
			}
			try {
				usuarios.add(new User(nome,opnioes));
			} catch (Exception e) {
				System.out.println(e.getMessage());
			}
		}
		
		Assert.assertEquals("Erro no getUsuarios", usuarios.size(),recomendacoes.getUsuarios().size());
		for (int i = 0; i < usuarios.size(); i++) {
			Assert.assertEquals("Erro no getUsuarios", usuarios.get(i).getNome(),recomendacoes.getUsuarios().get(i).getNome());
		}
	}

	/**
	 * testa os enderecos dos estabelecimentos presente no sistema.
	 */
	@Test
	public void testGetEnderecos() {
		Arquivo b = new Arquivo();
		
		try {
			b.lerArquivo("Estabelecimentos-v2.data");
		} catch (Exception e) {
			e.printStackTrace();
		}
		List<String> end = b.getLinhasDoArquivoLido();
		
		Assert.assertEquals("Erro no getEnderecos", end.size(),recomendacoes.getEnderecos().size());
		for (int i = 0; i < end.size(); i++) {
			Assert.assertEquals("Erro no getEnderecos", end.get(i),recomendacoes.getEnderecos().get(i));
		}
	}

	/**
	 * testa o arquivo de opnioes.
	 */
	@Test
	public void testGetOpinioes() {
		Arquivo a = new Arquivo();
		
		try {
			a.lerArquivo("Opinioes-v2.data");
		} catch (Exception e) {
			e.printStackTrace();
		}
		List<String> op = a.getLinhasDoArquivoLido();
		
		Assert.assertEquals("Erro no getOpinioes", op.size(),recomendacoes.getOpnioes().size());
		for (int i = 0; i < op.size(); i++) {
			Assert.assertEquals("Erro no getOpinioes", op.get(i),recomendacoes.getOpnioes().get(i));
		}
	}

	/**
	 * testa o algoritmo de popularidade Global.
	 * @throws Exception
	 * 		Caso o numero de opinioes pedido seja menor que 1.
	 */
	@Test
	public void testPopularidadeGlobal() throws Exception {
		
		List<String> global = recomendacoes.popularidadeGlobal(2);
		List<String> restaurantes = recomendacoes.getRestaurantes();
		
		Assert.assertTrue("Erro no popularidade Global",global.get(0).contains("Trailer do Marcus"));
		Assert.assertTrue("Erro no popularidade Global",global.get(1).contains("Bar do Cuscuz e Restaurante"));
		
		global = recomendacoes.popularidadeGlobal(10);
		for (int i = 0; i < global.size(); i++) {
			Assert.assertTrue("Erro no popularidade Global", global.get(i).equals(restaurantes.get(i)));
		}
	}
	
	/**
	 * Testa os tratamentos de erros no algoritmo de popularidade global.
	 */
	@Test
	public void testErroNoPopularidadeGlobal(){
		
		try {
			recomendacoes.popularidadeGlobal(-2);
			Assert.fail("Esperava excecao de quantidade negativa.");
		} catch (Exception e) {
			Assert.assertEquals("Erro no throws de popularidade Global","Deve ser passado no minimo 1 informacao",e.getMessage());
		}
		
		try {
			recomendacoes.popularidadeGlobal(0);
			Assert.fail("Esperava excecao de quantidade negativa.");
		} catch (Exception e) {
			Assert.assertEquals("Erro no throws de popularidade Global","Deve ser passado no minimo 1 informacao",e.getMessage());
		}
	}
	
	/**
	 * testa o algoritmo de popularidade simples.
	 */
	@Test
	public void testGetRestaurantes() {
		
		Assert.assertTrue("Erro no GetRestaurante",recomendacoes.getRestaurantes().get(0).contains("Trailer do Marcus"));
		Assert.assertTrue("Erro no GetRestaurante",recomendacoes.getRestaurantes().get(1).contains("Bar do Cuscuz e Restaurante"));
		Assert.assertTrue("Erro no GetRestaurante",recomendacoes.getRestaurantes().get(2).contains("Bonaparte"));
		Assert.assertTrue("Erro no GetRestaurante",recomendacoes.getRestaurantes().get(38).contains("Marmitaria da Mama"));

	}

	/**
	 * testa o algoritmo de popularidade personalizada.
	 * @throws Exception
	 * 		Caso o usuario seja null ou o numero de opnioes seja menor que 1.
	 */
	@Test
	public void testPopularidadePersonalizada() throws Exception {
	
		User usuario = recomendacoes.getUsuarios().get(0);
		List<String> r  = recomendacoes.PopularidadePersonalizada(usuario, 5);
		Assert.assertTrue("Erro no popularidade personalizada",usuario.getNome().equals("Nazareno"));
		Assert.assertEquals("Erro no popularidade Personalizada", "Giraffas",r.get(0));
		Assert.assertEquals("Erro no popularidade Personalizada", "Marmitaria ArtCulinária",r.get(1));
		Assert.assertEquals("Erro no popularidade Personalizada", "Trailer do Marcus",r.get(2));
		Assert.assertEquals("Erro no popularidade Personalizada", "Restaurante Lay China",r.get(3));
		Assert.assertEquals("Erro no popularidade Personalizada", "Cantina do Hall das Placas",r.get(4));
		
	}
	/**
	 * testa o metodo para ordena os restaurantes por tipo de refeicao;
	 * @throws Exception 
	 * 		Caso o arquivo nao exista.
	 */
	@Test
	public void testOrdenacaoPorRefeicao() throws Exception{
		Arquivo a = new Arquivo();
		a.lerArquivo("Estabelecimentos-v2.data");
		List<String> linhas = a.getLinhasDoArquivoLido();
		List<String> end = new ArrayList<String>();
		
		for (String linha : linhas) {
			String[] infos = linha.split(";");
			end.add(infos[2] + " | " + infos[0]);
		}
		Collections.sort(end);
		for (int i = 0; i < recomendacoes.ordenacaoPorRefeicao().size(); i++) {
			Assert.assertEquals("Erro no ordenacao por refeicao",end.get(i),recomendacoes.ordenacaoPorRefeicao().get(i));
		}
		
	}
	/**
	 * Testa o metodo de ordenacao por ordem alfabetica
	 * @throws Exception
	 * 		Caso o arquivo nao exista.
	 */
	@Test
	public void testOrdenacaoAlfabetica() throws Exception{
		Arquivo a = new Arquivo();
		a.lerArquivo("Opinioes-v2.data");
		List<String> linhas = a.getLinhasDoArquivoLido();
		List<String> end = new ArrayList<String>();
		
		
		String[] infos = linhas.get(0).split(";");
		for (int i = 2; i < infos.length; i++) {
			end.add(infos[i]);
		}
		
		Collections.sort(end);
		for (int i = 0; i < recomendacoes.ordenacaoAlfabetica().size(); i++) {
			Assert.assertEquals("Erro no ordenacao por refeicao",end.get(i),recomendacoes.ordenacaoAlfabetica().get(i));
		}
		
	}
	
	/**
	 * Testa o metodo de comparacao entre os dois algoritmos.
	 * @throws Exception
	 * 		Se o numero de itens for maior que o numero de estabelecimentos.
	 */
	@Test
	public void testComparaAlgoritmos() throws Exception{
		
		String comparacao = recomendacoes.comparaAlgoritmos(20);
		String[] percents = comparacao.split("\n");
		
		Assert.assertTrue("Erro no compara algoritmo", Double.parseDouble(percents[0]) > Double.parseDouble(percents[1]));
		
		comparacao = recomendacoes.comparaAlgoritmos(39);
		percents = comparacao.split("\n");
		
		Assert.assertTrue("Erro no compara algoritmo", Double.parseDouble(percents[0]) > 99.0);
		Assert.assertTrue("Erro no compara algoritmo", Double.parseDouble(percents[1]) > 99.0);
		
	}	
	/**
	 * testa os tratamentos de erros no algoritmo de popularidade personalizada.
	 */
	@Test
	public void testErroNoPopularidadePersonalizada(){
		
		User usuario = recomendacoes.getUsuarios().get(0);
		
		try {
			recomendacoes.PopularidadePersonalizada(null, 2);
			Assert.fail("Esperava excecao de usuario null.");
		} catch (Exception e) {
			Assert.assertEquals("Erro no throws de popularidade personalizada", "Usuario nao pode ser nulo",e.getMessage());
			
		}
		
		try {
			recomendacoes.PopularidadePersonalizada(usuario, 0);
			Assert.fail("Esperava excecao de usuario null.");
		} catch (Exception e) {
			Assert.assertEquals("Erro no throws de popularidade personalizada", "Numero de opnioes invalido",e.getMessage());
			
		}
	}
}
